package strategy;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;

import windows.MainWindow;

public class RC4_CBC implements AlgorithmInteface,ModerAlgorithmInterface {

	private String result;
	private int[] S;
	private int[] T;
	private int keylen;
	private  byte[] text;
	private byte[] key;
	private final byte iv = 'a';
	
	private File openFile;
	private File saveFile;

	private MainWindow ref;
	private MainWindow ref2;
	
	private byte[] ciphertext;

	public RC4_CBC(String text, String key, MainWindow reference) {
		this.text = text.getBytes();
		this.key = key.getBytes();
		keylen = this.key.length;
		ref = reference;
		KSA();
	}
	
	public RC4_CBC(File in, File out, String key, MainWindow reference) {
		openFile = in;
		saveFile = out;
		this.key = key.getBytes();
		keylen = this.key.length;
		ref2 = reference;
		KSA();
	}

	public void KSA() {
		if (keylen < 1 || keylen > 256) {
			System.out.println("Hibas kulcs.");
		}
		else {
			S = new int[256];
			T = new int[256];
			for (int i = 0; i < 256; i++) {
				S[i] = i;
				T[i] = key[i % keylen];
			}
			int j = 0;
			for (int i = 0; i < 256; i++) {
				j = (j + S[i] + T[i]) % 256;
				S[i] ^= S[j];
				S[j] ^= S[i];
				S[i] ^= S[j];
			}
		}
	}

	@Override
	public void decrypt() {
		ciphertext = new byte[text.length];
		int i = 0, j = 0, k, t;
		for (int counter = 0; counter < text.length; counter++) {
			i = (i + 1) % 256;
			j = (j + S[i]) % 256;
			S[i] ^= S[j];
			S[j] ^= S[i];
			S[i] ^= S[j];
			t = (S[i] + S[j]) % 256;
			k = S[t];
			
			if (counter == 0) {
				ciphertext[counter] = (byte) ((text[counter] ^ k) ^ iv);
			}
			else {
				ciphertext[counter] = (byte) ((text[counter] ^ k) ^ text[counter-1]);
			}
		}

		try {
			result = new String(ciphertext);
		} catch (Exception e) {
			e.printStackTrace();
		}

		update();
	}

	@Override
	public void encrypt() {
		ciphertext = new byte[text.length];
		int i = 0, j = 0, k, t;
		for (int counter = 0; counter < text.length; counter++) {
			i = (i + 1) % 256;
			j = (j + S[i]) % 256;
			S[i] ^= S[j];
			S[j] ^= S[i];
			S[i] ^= S[j];
			t = (S[i] + S[j]) % 256;
			k = S[t];
			
			if (counter == 0) {
				ciphertext[counter] = (byte) ((text[counter] ^ iv) ^ k);
			}
			else {
				ciphertext[counter] = (byte) ((text[counter] ^ ciphertext[counter-1]) ^ k);
			}
		}

		try {
			result = new String(ciphertext);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		update();
	}

	@Override
	public void autoDecrypt() {

	}

	@Override
	public void update() {
		if (ref != null)
			ref.rc4CBCUpdate(result);
	}

	public void encryptModern() {
		text = toByteArray(openFile);
		System.out.println("itt");
		encrypt();
		System.out.println("itt2");
		try {
			FileOutputStream out = new FileOutputStream(saveFile.getAbsolutePath());
//			BufferedWriter out = new BufferedWriter(new FileWriter(saveFile));
			out.write(ciphertext);
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
		updateModern();
	}
	
    public static byte[] toByteArray(File file) {  
        int length = (int) file.length();  
        byte[] array = new byte[length];  
        InputStream in;
		try {
			in = new FileInputStream(file);
	        int offset = 0;  
	        while (offset < length) {  
	            int count = in.read(array, offset, (length - offset));  
	            offset += length;  
	        }  
	        in.close();  
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  

        return array;  
    }  

	public void decryptModern() {
		text = toByteArray(openFile);
		decrypt();
		try {
			FileOutputStream out = new FileOutputStream(saveFile.getAbsolutePath());
//			BufferedWriter out = new BufferedWriter(new FileWriter(saveFile));
			out.write(ciphertext);
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		updateModern();
	}

	@Override
	public void updateModern() {
		// TODO Auto-generated method stub
		ref2.rc4AdvanceUpdate();
	}

}
